/*
 * @(#)ItemDisplayScreen.java	1.9 04/06/14
 *
 * Copyright (c) 2000-2004 Sun Microsystems, Inc. All rights reserved.
 * PROPRIETARY/CONFIDENTIAL
 * Use is subject to license terms
 */

package example.pim;

import java.io.ByteArrayOutputStream;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.DateField;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemCommandListener;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.TextField;
import javax.microedition.pim.Contact;
import javax.microedition.pim.Event;
import javax.microedition.pim.PIM;
import javax.microedition.pim.PIMException;
import javax.microedition.pim.PIMItem;
import javax.microedition.pim.ToDo;
import sample.pim.PdapMobileClient;

import javax.microedition.io.*;
import java.io.*;

/**
 * Demonstrate the use of JSR 75 PIM APIs
 */
public class ItemDisplayScreen extends Form implements CommandListener, ItemCommandListener {
    
    private final Command editArrayCommand = new Command("Edit", Command.OK, 1);
    private final Command editBooleanCommand = new Command("Edit", Command.OK, 1);
    private final Command commitCommand = new Command("Commit", Command.OK, 2);
    private final Command backCommand = new Command("Back", Command.BACK, 1);
    private final Command showVCard = new Command("Show vCard", Command.SCREEN, 5);
    private final Command showVCalendar = new Command("Show vCalendar", Command.SCREEN, 5);
    private final Command addField = new Command("Add Field", Command.SCREEN, 2);
    private final Command removeField = new Command("Remove Field", Command.SCREEN, 3);
    
    private final Command syncGContacts = new Command("Upload to GContacts", Command.SCREEN, 4);     //edited
    private PdapMobileClient client;
    private StringItem helloStringItem;
//    private static String midlet.guser = "";
//    private static String midlet.gpass = "";
    
    private final PIMDemo midlet;
    private final ItemSelectionScreen caller;
    private final PIMItem item;
    private final Hashtable fieldTable = new Hashtable(); // maps field indices to items
    private Vector fi;// = new Vector();               //to hold field & its index
    
    private String url = "http://localhost:8080/contacts";//"http://sharifgae.appspot.com/contacts";//
    private String param;
    
    public ItemDisplayScreen(PIMDemo midlet,
            ItemSelectionScreen caller, PIMItem item) throws PIMException {
        
        super("PIM Item");
        this.midlet = midlet;
        this.caller = caller;
        this.item = item;
        
        populateForm();
        
        addCommand(backCommand);
        addCommand(commitCommand);
        setCommandListener(this);
    }
    
    private boolean isClassField(int field) {
        return item instanceof Contact && field == Contact.CLASS
                || item instanceof Event && field == Event.CLASS
                || item instanceof ToDo && field == ToDo.CLASS;
    }
    
    private void populateForm() throws PIMException {
        deleteAll();
        fieldTable.clear();
        int[] fields = item.getPIMList().getSupportedFields();
        boolean allFieldsUsed = true;
        for (int i = 0; i < fields.length; i++) {
            int field = fields[i];
            
            // exclude CLASS field
            if (isClassField(field)) {
                continue;
            }
            if (item.countValues(field) == 0) {
                allFieldsUsed = false;
                continue;
            }
            int dataType = item.getPIMList().getFieldDataType(field);
            String label = item.getPIMList().getFieldLabel(field);
            System.out.println("field="+field+", dataType="+dataType+", label="+label);
            Item formItem = null;
            switch (dataType) {
                case PIMItem.STRING: {
                    String sValue = "";
                    int style = TextField.ANY;
                    // cater for specific field styles
                    if (item instanceof Contact) {
                        switch (field) {
                            case Contact.EMAIL:
                                style = TextField.EMAILADDR;
                                break;
                            case Contact.TEL:
                                style = TextField.PHONENUMBER;
                                break;
                            case Contact.URL:
                                style = TextField.URL;
                                break;
                        }
                    }
                    try {
                        for( int c = 0; c < item.countValues(field); c++ ) {
                            sValue = item.getString(field, c);
                            if (sValue == null) {
                                sValue = "";
                            }
                            formItem = new TextField(label, sValue, 128, style);
                            if (formItem != null) {
                                append(formItem);
                                //fi.removeAllElements();
                                fi = new Vector();
                                fi.addElement( new Integer(field) );
                                fi.addElement( new Integer(c) );
                                fieldTable.put(formItem, fi);
                                formItem.addCommand(removeField);
                                formItem.setItemCommandListener(this);
                                System.out.println("String value appended.");
                            }
                        }
                        continue;
                    } catch (IllegalArgumentException e) {
                        formItem = new TextField(label, sValue, 128, TextField.ANY);
                        System.out.println("in try catch of String value");
                    }
                    break;
                }
                case PIMItem.BOOLEAN: {
                    formItem = new StringItem(label,
                            item.getBoolean(field, 0) ? "yes" : "no");
                    formItem.setDefaultCommand(editBooleanCommand);
                    System.out.println("Boolean value.");
                    break;
                }
                case PIMItem.STRING_ARRAY: {
                    String[] a = item.getStringArray(field, 0);
                    if (a != null) {
                        formItem = new StringItem(label, joinStringArray(a));
                        formItem.setDefaultCommand(editArrayCommand);
                    }
                    System.out.println("String array value.");
                    break;
                }
                case PIMItem.DATE: {
                    long time = item.getDate(field, 0);
                    int style = DateField.DATE_TIME;
                    // some fields are date only, without a time.
                    // correct for these fields:
                    if (item instanceof Contact) {
                        switch (field) {
                            case Contact.BIRTHDAY:
                                style = DateField.DATE;
                                break;
                        }
                    }
                    formItem = new DateField(label, style);
                    ((DateField) formItem).setDate(new Date(time));
                    System.out.println("PIMItem type is date");
                    break;
                }
                case PIMItem.INT: {
                    formItem = new TextField(label,
                            String.valueOf(item.getInt(field, 0)),
                            64, TextField.DECIMAL);
                    System.out.println("int value.");
                    break;
                }
                case PIMItem.BINARY: {
                    byte[] data = item.getBinary(field, 0);
                    if (data != null) {
                        formItem = new StringItem(label, data.length + " bytes");
                    }
                    System.out.println("binary value.");
                    break;
                }
            }
            if (formItem != null) {
                append(formItem);
                //fi.removeAllElements();
                fi = new Vector();
                fi.addElement( new Integer(field) );
                fieldTable.put(formItem, fi);
                
                formItem.addCommand(removeField);
                formItem.setItemCommandListener(this);
            }
            System.out.println("appending non string value.");
        }
        if (item instanceof Contact) {
            addCommand(showVCard);
            
            addCommand(syncGContacts);
        } else {
            addCommand(showVCalendar);
        }
        if (!allFieldsUsed) {
            addCommand(addField);
        } else {
            removeCommand(addField);
        }
    }
    
    public void commandAction(Command command, Displayable displayable) {
        if (command == backCommand) {
            try {
                getUserData();
            } catch (Exception e) {
                // ignore; store what can be stored of the data
            }
            try {
                caller.populateList();
            } catch (Exception e) {
                // ignore again; show what can be shown of the list
            }
            Display.getDisplay(midlet).setCurrent(caller);
        } else if (command == commitCommand) {
            commit();
        } else if (command == showVCard) {
            showItem("VCARD/2.1");
        } else if (command == showVCalendar) {
            showItem("VCALENDAR/1.0");
        } else if (command == syncGContacts) {
            System.out.println(midlet.guser+":"+midlet.gpass);
            if( !midlet.guser.equals("") && !midlet.gpass.equals("") ) {
                syncGoogleContacts();
                return;
            }
            final TextField ut = new TextField( "Username:", midlet.guser, 128, TextField.EMAILADDR );
            final TextField pt = new TextField( "Password:", midlet.gpass, 128, TextField.PASSWORD );
            final Command okCommand = new Command("OK", Command.OK, 1);
            final Command cancelCommand = new Command("Cancel", Command.CANCEL, 1);
            Form form = new Form("Enter Google credentials", new TextField[]{ut, pt});
            form.addCommand(okCommand);
            form.addCommand(cancelCommand);
            form.setCommandListener(new CommandListener() {
                public void commandAction(Command command, Displayable d) {
                    if (command == okCommand) {
                        midlet.guser = ut.getString(); midlet.gpass = pt.getString();
                        if( midlet.guser.equals("") || midlet.gpass.equals("") )
                            return;
                        syncGoogleContacts();
                    }
                    Display.getDisplay(midlet).setCurrent(ItemDisplayScreen.this);
                    System.out.println(midlet.guser+":"+midlet.gpass);
                }
            });
            Display.getDisplay(midlet).setCurrent(form);
        } else if (command == addField) {
            addField();
        }
    }
    
    public void commandAction(Command command, final Item formItem) {
//        final int field = ((Integer) fieldTable.get(formItem)).intValue();
        Vector v = ((Vector) fieldTable.get(formItem));
        final int field = ((Integer)v.elementAt(0)).intValue();
        int index = 0;
        if( v.size() == 2 )
            index = ((Integer)v.elementAt(1)).intValue();
        
        if (command == editBooleanCommand) {
            boolean newValue = !item.getBoolean(field, 0);
            item.setBoolean(field, 0, PIMItem.ATTR_NONE, newValue);
            ((StringItem) formItem).setText(newValue ? "yes" : "no");
        } else if (command == editArrayCommand) {
            String label = item.getPIMList().getFieldLabel(field);
            final String[] a = item.getStringArray(field, 0);
            final TextField[] textFields = new TextField[a.length];
            for (int i = 0; i < a.length; i++) {
                String elementLabel =
                        item.getPIMList().getArrayElementLabel(field, i);
                textFields[i] = new TextField(elementLabel, a[i], 128, TextField.ANY);
            }
            Form form = new Form(label, textFields);
            final Command okCommand = new Command("OK", Command.OK, 1);
            final Command cancelCommand = new Command("Cancel", Command.CANCEL, 1);
            form.addCommand(okCommand);
            form.addCommand(cancelCommand);
            form.setCommandListener(new CommandListener() {
                public void commandAction(Command command, Displayable d) {
                    if (command == okCommand) {
                        for (int i = 0; i < textFields.length; i++) {
                            a[i] = textFields[i].getString();
                        }
                        item.setStringArray(field, 0, item.getAttributes(field, 0), a);
                        ((StringItem) formItem).setText(joinStringArray(a));
                    }
                    Display.getDisplay(midlet).setCurrent(ItemDisplayScreen.this);
                }
            });
            Display.getDisplay(midlet).setCurrent(form);
        } else if (command == removeField) {
            //for( int c = 0; c < item.countValues(field); c++ )
            item.removeValue(field, index);     //index here
            try {
                populateForm();
            } catch (PIMException e) { }
            /*
            for (int i = size() - 1; i >=0; i--) {
                if (get(i) == formItem) {
                    delete(i);
                    break;
                }
            }*/
        }
    }
    
    private void commit() {
        try {
            getUserData();
            item.commit();
            populateForm();
        } catch (Exception e) {
            midlet.reportException(e, this);
        }
    }
    
    private void getUserData() throws NumberFormatException {
        int itemCount = size();
        for (int i = 0; i < itemCount; i++) {
            Item formItem = get(i);
            System.out.println( formItem instanceof DateField );
            //int field = ((Integer) fieldTable.get(formItem)).intValue();
            Vector v = ((Vector) fieldTable.get(formItem));
            int field = ((Integer)v.elementAt(0)).intValue();//final int 
            
            if( field == Contact.UID )      //UID cant be edited
                continue;
            
            int index = 0;
            if( v.size() == 2 )
                index = ((Integer)v.elementAt(1)).intValue();
            
            if (item.countValues(field) < 1) {
                // No data in field. This can happen if, for example, a
                // value is adding to PUBLIC_KEY, causing values of
                // PUBLIC_KEY_STRING to be erased.
                continue;
            }
            int dataType = item.getPIMList().getFieldDataType(field);
            System.out.println("i="+ i + ", size="+v.size()+", field="+field+", index="+index+", dataType="+dataType);
            switch (dataType) {
                case PIMItem.STRING: {
                    String s = ((TextField) formItem).getString();
                    try {
                        //item.setString(field, 0, PIMItem.ATTR_NONE, s);
                        item.setString(field, index, PIMItem.ATTR_NONE, s);              //index here
                    } catch (IllegalArgumentException e) {
                        // this was a read-only field (UID)
                        e.printStackTrace();
                    }
                    break;
                }
                case PIMItem.DATE: {
                    System.out.println("i m here");
                    long time = ((DateField) formItem).getDate().getTime();
                    System.out.println("time="+time);
                    try {
                        item.setDate(field, 0, PIMItem.ATTR_NONE, time);
                    } catch (IllegalArgumentException e) {
                        // this was a read-only field (REVISION)
                    }
                    break;
                }
                case PIMItem.INT: {
                    String s = ((TextField) formItem).getString();
                    int j = Integer.parseInt(s);
                    item.setInt(field, 0, PIMItem.ATTR_NONE, j);
                    break;
                }
            }
        }
    }
    
    private void addField() {
        int[] allFields = item.getPIMList().getSupportedFields();
        final Vector unusedFields = new Vector();
        for (int i = 0; i < allFields.length; i++) {
//            if (item.countValues(allFields[i]) == 0 && !isClassField(allFields[i])) {
            unusedFields.addElement(new Integer(allFields[i]));
//            }
        }
        final List fieldList = new List("Select a field to add", List.IMPLICIT);
        for (Enumeration e = unusedFields.elements(); e.hasMoreElements();) {
            int field = ((Integer) e.nextElement()).intValue();
            fieldList.append(item.getPIMList().getFieldLabel(field), null);
        }
        fieldList.addCommand(new Command("Cancel", Command.CANCEL, 1));
        fieldList.setSelectCommand(new Command("Add", Command.OK, 1));
        fieldList.setCommandListener(new CommandListener() {
            public void commandAction(Command c, Displayable d) {
                if (c.getCommandType() == Command.OK) {
                    try {
                        int index = fieldList.getSelectedIndex();
                        int field = ((Integer) unusedFields.elementAt(index))
                        .intValue();
                        addField(field);
                    } catch (IllegalArgumentException iae) {
                        midlet.reportException(iae, ItemDisplayScreen.this);
                    }
                    try {
                        getUserData();
                        populateForm();
                    } catch (Exception e) {
                        midlet.reportException(e, ItemDisplayScreen.this);
                    }
                }
                Display.getDisplay(midlet).setCurrent(ItemDisplayScreen.this);
            }
        });
        Display.getDisplay(midlet).setCurrent(fieldList);
    }
    
    private void addField(int field) {
        switch (item.getPIMList().getFieldDataType(field)) {
            case PIMItem.STRING:
                item.addString(field, PIMItem.ATTR_NONE, "");
                break;
            case PIMItem.STRING_ARRAY: {
                int[] supportedElements =
                        item.getPIMList().getSupportedArrayElements(field);
                int arraySize = 0;
                for (int i = 0; i < supportedElements.length; i++) {
                    arraySize = Math.max(arraySize, supportedElements[i] + 1);
                }
                String[] a = new String[arraySize];
                for (int i = 0; i < a.length; i++) {
                    a[i] = "";
                }
                item.addStringArray(field, PIMItem.ATTR_NONE, a);
                break;
            }
            case PIMItem.BINARY:
                item.addBinary(field, PIMItem.ATTR_NONE, new byte[16], 0, 16);
                break;
            case PIMItem.BOOLEAN:
                item.addBoolean(field, PIMItem.ATTR_NONE, false);
                break;
            case PIMItem.DATE:
                item.addDate(field, PIMItem.ATTR_NONE, new Date().getTime());
                break;
            case PIMItem.INT:
                item.addInt(field, PIMItem.ATTR_NONE, 0);
        }
        
    }
    
    private void showItem(String format) {
        try {
            getUserData();
            populateForm();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            PIM.getInstance().toSerialFormat(item, baos, "UTF-8", format);
            String s = new String(baos.toByteArray(), "UTF-8");
            Alert a = new Alert(format, s, null, AlertType.INFO);
            a.setTimeout(Alert.FOREVER);
            Display.getDisplay(midlet).setCurrent(a, this);
        } catch (Exception e) {
            midlet.reportException(e, this);
        }
    }
    
    private void syncGoogleContacts() {
        new Thread(new Runnable() {
            public void run() {
                try {
//                    String[] params = new String[10];
//                    params[0] = "--username=" + (midlet.guser.endsWith("@gmail.com")?midlet.guser:midlet.guser+"@gmail.com");       //
//                    params[1] = "--password=" + midlet.gpass;       //
//                    //params[2] = "--action=list";
//                    params[2] = "--action=add";
//
                    int field;
//                    TextField tf = null;
//                    StringItem si = null;
                    String name = "";
//                    //String fname = "";
                    String tel = "";
                    String email = "";
                    String web = "";
//
                    String keyval;
//                    String itemval = "";
                    String ret = "";
                    for( Enumeration e = fieldTable.keys(); e.hasMoreElements(); ) {
                        Item it = (Item)e.nextElement();
                        if( it instanceof TextField )
                            keyval = ((TextField)it).getString();
                        else if( it instanceof StringItem )
                            keyval = ((StringItem)it).getText();
                        else
                            continue;
////                        Integer intg = (Integer)fieldTable.get(it);
////                        field = intg.intValue();            //check - item iof Contact
                        Vector v = ((Vector) fieldTable.get(it));
                        field = ((Integer)v.elementAt(0)).intValue();
                        //int index = 0;
                        //if( v.size() == 2 )
                        //    index = ((Integer)v.elementAt(1)).intValue();
                        switch( field ) {
                            case Contact.NAME:
                            case Contact.FORMATTED_NAME:        //if fname, thn save it, discard whole name
//                                params[3] = "--name=" + keyval;
                                name = keyval;
                                break;
                            case Contact.TEL:
//                                params[4] = "--phone1=" + keyval + ",rel:http://schemas.google.com/g/2005#mobile";
                                tel = keyval;
                                break;
                            case Contact.EMAIL:
//                                params[5] = "--email1=" + keyval + ",rel:http://schemas.google.com/g/2005#work";
                                email = keyval;
                                //itemval += it.getLabel() + "=" + (( si == null ) ? tf.getString() : si.getText()) + "  ";
                                break;
                            case Contact.URL:
                                web = keyval;
                                break;
                        }
                    }
                    
                    param = "username=" + midlet.guser + "&password=" + midlet.gpass + "&name=" + name + "&phone=" + tel + "&email=" + email;
                    System.out.println("param="+param);
                    
                    if(!web.equals(""))
                        ret = "Contact already added in Google Contacts.";  //1) do u want to add again?(same email), 2) url check for google/m8
                    else {
                        /*
                        client = new PdapMobileClient();
                        ret = client.testoperation(params);
                        //item.setString(Contact.URL, 118, PIMItem.ATTR_NONE, ret);         //exception occurs
                        item.addString(Contact.URL, PIMItem.ATTR_NONE, ret);
                        item.commit();
                         */
                        ret = midlet.sendHttpPost(param);
                        
                    }
                    Alert a = new Alert("Done", ret, null, AlertType.INFO);
                    a.setTimeout(Alert.FOREVER);
                    Display.getDisplay(midlet).setCurrent(a, ItemDisplayScreen.this);
                } catch (Exception e) {
                    midlet.reportException(e, ItemDisplayScreen.this);
                }
            }
        }).start();
    }
    
    private String joinStringArray(String[] a) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < a.length; i++) {
            if (a[i] != null && a[i].length() > 0) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(a[i]);
            }
        }
        return sb.toString();
    }
    
}
